package cn.com.bluemoon.daps.standard.controller;


import cn.com.bluemoon.daps.api.sys.RemoteSysDeptService;
import cn.com.bluemoon.daps.common.datascope.BmPermission;
import cn.com.bluemoon.daps.common.datascope.IgnorePermission;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.enums.DatabaseType;
import cn.com.bluemoon.daps.common.enums.StandardAuditStatus;
import cn.com.bluemoon.daps.common.mp.IBmService;
import cn.com.bluemoon.daps.common.webhook.Authors;
import cn.com.bluemoon.daps.standard.entity.DapStandardAuditVersionMain;
import cn.com.bluemoon.daps.standard.entity.DapStandardBasic;
import cn.com.bluemoon.daps.standard.entity.DapStandardIndex;
import cn.com.bluemoon.daps.standard.service.DapStandardBasicService;
import cn.com.bluemoon.daps.standard.service.DapStandardDataTypeService;
import cn.com.bluemoon.daps.standard.service.DapStandardIndexService;
import cn.com.bluemoon.daps.standard.service.DapStandardModifyService;
import cn.com.bluemoon.daps.standard.vo.BasicStandardAndDicVo;
import cn.com.bluemoon.daps.standard.vo.BasicStandardAndDicVo.ModelTableInfo;
import cn.com.bluemoon.daps.standard.vo.BasicStandardFormVo;
import cn.com.bluemoon.daps.standard.vo.BasicStandardMatchVo;
import cn.com.bluemoon.daps.standard.vo.KeywordType;
import cn.com.bluemoon.daps.system.entity.DapSystemDepartment;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 基础标准表 前端控制器
 * </p>
 *
 * @author admin
 * @since 2020-08-04
 */
@Api(tags = "基础标准")
@RestController
@Slf4j
@Authors(value = @Authors.Author(name = "Jarod.Kong", desc = "基础标准查询", devTime = ""))
@RequestMapping("/dapStandardBasic")
public class DapStandardBasicController {
    private static final String SYS_CATEGORY_QUERY_ALL_ID = "#all";
    @Autowired
    private DapStandardBasicService dapStandardBasicService;

    @Autowired
    private DapStandardIndexService dapStandardIndexService;

    @Autowired
    private DapStandardModifyService dapStandardModifyService;

    @Autowired
    private DapStandardDataTypeService dataTypeService;

    @Autowired
    private RemoteSysDeptService remoteSysDeptService;

    @GetMapping("/dept/list")
    @ApiOperation(value = "获取部门信息")
    @IgnorePermission(name = "忽略权限")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = DapSystemDepartment.class)})
    public ResultBean<List<DapSystemDepartment>> list(@RequestParam(value = "type") @ApiParam("标准类型：1基础标准 2指标标准") Integer type) {
        ResultBean<List<DapSystemDepartment>> resultBean = remoteSysDeptService.listAll();
        if (!resultBean.isOk()) {
            return ResultBean.ok(Collections.emptyList());
        }
        Set<String> deptIds;
        if (type.equals(1)) {
            deptIds = dapStandardBasicService.list(dapStandardBasicService.bmLambdaQuery().select(DapStandardBasic::getDepartmentId))
                    .stream().map(DapStandardBasic::getDepartmentId).collect(Collectors.toSet());
        } else {
            deptIds = dapStandardIndexService.list(dapStandardIndexService.bmLambdaQuery().select(DapStandardIndex::getManagementDepartmentId))
                    .stream().map(DapStandardIndex::getManagementDepartmentId).collect(Collectors.toSet());
        }
        List<DapSystemDepartment> res = resultBean.getContent().stream().filter(d -> deptIds.contains(d.getId())).collect(Collectors.toList());
        return ResultBean.ok(res);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @BmPermission(value = "standard:query:basic:query", name = "基础标准列表查询")
    @PostMapping("/list")
    @ApiOperation(value = "根据主题id和层级分类获取分类列表数据-用于分类列表中")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = BasicStandardAndDicVo.class)})
    public ResultBean<?> queryBasic(@RequestBody @Valid BasicStandardFormVo basicStandardFormVo) {
        LambdaQueryWrapper<DapStandardBasic> where = queryBasicWrapper(basicStandardFormVo, false);
        IPage<DapStandardBasic> page = dapStandardBasicService.page(basicStandardFormVo.toMpPage(), where);
        page.convert(d -> {
            BasicStandardAndDicVo vo = new BasicStandardAndDicVo(d);
            dapStandardBasicService.transferDicInfo(d, vo);
            // 增加flag 标识该标准在流程变更中存在待发布数据，是为true，否false
            boolean auditChanging = dapStandardModifyService.analyseAuditChanging(vo);
            vo.setAuditChanging(auditChanging);
            return vo;
        });
        return IBmService.toAntDvPageTool(page);
    }

    @BmPermission(value = "standard:query:basic:query", name = "模糊查询基础标准数据")
    @PostMapping("/match")
    @ApiOperation(value = "模糊查询基础标准数据-模型字段模糊查询")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = BasicStandardMatchVo.OutVo.class)})
    public ResultBean<List<BasicStandardMatchVo.OutVo>> matchStd(@RequestBody @Valid BasicStandardMatchVo.InVo matchVo) {
        // 增加逻辑，模糊查询中keyword为空/null时候，返回空
        if (StringUtils.isBlank(StringUtils.trim(matchVo.getKeyword()))) {
            log.debug("模糊查询中，关键字为空/null，返回[]");
            return ResultBean.ok(Collections.emptyList());
        }
        LambdaQueryWrapper<DapStandardBasic> where = queryBasicWrapper(matchVo.toPageVo(), matchVo.isRightMatch());
        List<DapStandardBasic> list = dapStandardBasicService.list(where);
        DatabaseType dbType = matchVo.toDbTypeOrDefault(null);
        return ResultBean.ok(list).convert(l -> l.stream()
                .map(d -> {
                    BasicStandardMatchVo.OutVo outVo = new BasicStandardMatchVo.OutVo(d);
                    // 增加获取数据库类型对应的默认字段类型
                    if (d != null && d.getDataType() != null) {
                        Optional<String> defaultVal = dataTypeService.getDefaultValByDbTypeAndCodeOnCache(dbType, d.getDataType());
                        defaultVal.ifPresent(outVo::setDataType);
                    }
                    return outVo;
                }).collect(Collectors.toList()));
    }

    /**
     * 构建查询正式发布的标准数据
     *
     * @param formVo     条件
     * @param rightMatch true做匹配 name/eng_name/define_desc false全匹配
     * @return 构建查询正式发布的标准数据
     */
    @SuppressWarnings("rawtypes")
    private LambdaQueryWrapper<DapStandardBasic> queryBasicWrapper(BasicStandardFormVo formVo, boolean rightMatch) {
        KeywordType kt = formVo.getKeywordType();
        final boolean fEnPredicate = KeywordType.FieldName.equals(kt) || kt == null;
        final boolean fZhPredicate = KeywordType.FieldNameZh.equals(kt) || kt == null;
        final boolean fDescPredicate = KeywordType.FieldDesc.equals(kt) || kt == null;
        LambdaQueryWrapper<DapStandardBasic> basicWrapper = dapStandardBasicService.bmLambdaQuery()
                .orderByAsc(DapStandardBasic::getName)
                .eq(DapStandardBasic::getPublishNewest, Boolean.TRUE)
                .eq(StringUtils.isNotBlank(formVo.getTopicId()), DapStandardBasic::getTopicId, formVo.getTopicId())
                .eq(StringUtils.isNotBlank(formVo.getCategory1()) &&
                                !SYS_CATEGORY_QUERY_ALL_ID.equalsIgnoreCase(formVo.getCategory1()),
                        DapStandardBasic::getFirstCategory, formVo.getCategory1())
                .eq(StringUtils.isNotBlank(formVo.getCategory2()) &&
                                !SYS_CATEGORY_QUERY_ALL_ID.equalsIgnoreCase(formVo.getCategory2()),
                        DapStandardBasic::getSecondCategory, formVo.getCategory2())
                .eq(StringUtils.isNotBlank(formVo.getCategory3()) &&
                                !SYS_CATEGORY_QUERY_ALL_ID.equalsIgnoreCase(formVo.getCategory3()),
                        DapStandardBasic::getThirdCategory, formVo.getCategory3())
                .eq(StringUtils.isNotBlank(formVo.getDepartmentId()) &&
                                !SYS_CATEGORY_QUERY_ALL_ID.equalsIgnoreCase(formVo.getDepartmentId()),
                        DapStandardBasic::getDepartmentId, formVo.getDepartmentId());
        if (rightMatch) {
            return basicWrapper
                    .and(StringUtils.isNotBlank(formVo.getKeyword()), wrapper ->
                            wrapper.likeRight(fZhPredicate, DapStandardBasic::getName, formVo.getKeyword().trim())
                                    .or()
                                    .likeRight(fEnPredicate, DapStandardBasic::getEngName, formVo.getKeyword().trim())
                                    .or()
                                    .likeRight(fDescPredicate, DapStandardBasic::getBusinessDefine, formVo.getKeyword().trim()));
        } else {
            return basicWrapper
                    .and(StringUtils.isNotBlank(formVo.getKeyword()), wrapper ->
                            wrapper.like(fZhPredicate, DapStandardBasic::getName, formVo.getKeyword().trim())
                                    .or()
                                    .like(fEnPredicate, DapStandardBasic::getEngName, formVo.getKeyword().trim())
                                    .or()
                                    .like(fDescPredicate, DapStandardBasic::getBusinessDefine, formVo.getKeyword().trim()));
        }
    }

    @BmPermission(value = "standard:query:basic:delete", name = "基础标准删除")
    @ApiResponses({@ApiResponse(code = 200, message = "ok", response = ModelTableInfo.class)})
    @GetMapping({"/referenced/{id}"})
    @ApiOperation("删除数据前置判断，是否已被引用标准，不为空表示存在引用")
    public ResultBean<?> deletePre(@PathVariable String id) {
        List<ModelTableInfo> modelTableInfos = dapStandardBasicService.relateModelTableDataById(id);
        return ResultBean.ok(modelTableInfos);
    }

    /**
     * @param id 标准id
     * @return {@link ResultBean}
     * @since 2020年10月12日19:43:13 删除功能调整（期初理解为直接进行对标准删除，而今天落地确认为
     * <em>删除标准的业务逻辑是：启动一个删除的流程审批数据
     * （即变更类型为{@link DapStandardAuditVersionMain#getModifyType()} == 3以及变更状态为{@link StandardAuditStatus#草稿}的流程数据）</em>
     * 而最终是否删除标准，取决于是否通过待审批，若待审批通过则对{@link DapStandardAuditVersionMain#getModifyType()} == 3进行删除整个标准的流程数据和引用关系
     * 注意：其中{@link DapStandardAuditVersionMain#getModifyType()} == 3的流程数据是不可编辑的、
     * 并且要确保{@link DapStandardAuditVersionMain#getModifyType()} 一直为3（删除）来确保通过审批进行删除
     */
    @BmPermission(value = "standard:query:basic:delete", name = "发起删除审批流程")
    @ApiResponses({@ApiResponse(code = 200, message = "ok", response = ResultBean.class)})
    @DeleteMapping({"/{id}"})
    @ApiOperation("确定删除数据，及其相应联级数据")
    public ResultBean<?> deleteAudit(@PathVariable String id) {
        dapStandardModifyService.deleteAudit(id, 0);
        return ResultBean.ok();
    }

    @BmPermission(value = "standard:query:basic:view", name = "基础标准查看")
    @GetMapping("/{id}")
    @ApiOperation(value = "根据标准id获取标准数据和标准字典数据和分布信息")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = BasicStandardAndDicVo.class)})
    public ResultBean<BasicStandardAndDicVo> basicGet(@PathVariable String id) {
        BasicStandardAndDicVo basicStandardAndDicVo = dapStandardModifyService.getBasicStandardAndDicVo(id);
        List<ModelTableInfo> modelTableInfos = dapStandardBasicService.relateModelTableDataById(id);
        basicStandardAndDicVo.setDistributions(modelTableInfos);
        dapStandardBasicService.transferDicInfo(basicStandardAndDicVo, basicStandardAndDicVo);
        // 增加flag 标识该标准在流程变更中存在待发布数据，是为true，否false
        boolean auditChanging = dapStandardModifyService.analyseAuditChanging(basicStandardAndDicVo);
        basicStandardAndDicVo.setAuditChanging(auditChanging);
        return ResultBean.ok(basicStandardAndDicVo);
    }

}
